VI.FUME
20 實際建立一筆Patient的FUME Mapping
在談完FLASH的幾個基本語法之後,我們來看一下FUME Designer Playground的範例Patient Resource
這邊先上一個一模一樣的文件
#INPUT:
{
"mrn": "PP875023983",
"status": "active",
"ssn": "123-45-6789",
"passport_number": "7429184766",
"passport_country": "USA",
"first_name": "Jessica",
"last_name": "Rabbit",
"birth_date": "1988-06-22",
"sex": "F",
"address": {
"city_name": "Orlando",
"state": "FL",
"street_name": "Buena Vista",
"house_number": 1375,
"zip_code": "3456701",
"lat": 28.3519592,
"long": -81.417283
},
"phones": [
{
"type": "HOME",
"number": "+1 (407) 8372859"
},
{
"type": "CELL",
"number": "+1 (305) 9831195"
}
],
"primary_doctor": {
"full_name": "Dr. Dolittle",
"license": "1-820958"
}
}
#FUME:
/* FLASH script example for FHIR version 4.0 Patient */
Instance: $pid := $uuid()
InstanceOf: Patient
* identifier
* system = $urn
* value = 'urn:uuid:' & $pid
* identifier
* system = $exampleMrn
* value = mrn
* identifier
* system = $ssn
* value = ssn
* identifier
* system = $passportPrefix & passport_country
* value = passport_number
* active = status='active'
* name
* given = first_name
* family = last_name
* birthDate = birth_date
* gender = $translate(sex, 'gender')
* (address).address
* city = city_name
* state = state
* country = 'USA'
* line = $join([$string(house_number),street_name], ' ')
* postalCode = zip_code
* extension
* url = $extGeolocation
* extension
* url = 'latitude'
* valueDecimal = lat
* extension
* url = 'longitude'
* valueDecimal = long
* (phones).telecom
* system = 'phone'
* value = number
* use = (type='HOME'?'home':type='CELL'?'mobile')
* generalPractitioner
* identifier
* value = primary_doctor.license
* type.coding
* system = 'http://terminology.hl7.org/CodeSystem/v2-0203'
* code = 'MD'
* display = primary_doctor.full_name
* reference = $literal('Practitioner', {'identifier': primary_doctor.license})
左側的INPUT應該很好理解,這裡唯一要注意的地方是,
JSON是容許純數字的內容的,在填入資料與撰寫FUME Mapping時要特別注意型別
直接跳向FUME的部分,這才是今天的重點:
02 Instance: $pid := $uuid()
令一個變數$pid = function uuid(),這個function會生成一組uuid給變數$pid,而Instance的logical id被指派給$pid
03 InstanceOf: Patient
宣告該Resource的型別為Patient,宣告時其實FUME就會去檢查哪些屬性項是屬於Patient這個Resource了,
若有不合格式的屬性項,FUME會回報錯誤
04 * identifier
05 * system = $urn
06 * value = 'urn:uuid:' & $pid
第一組Patient.identifier,
identifier.system是$urn這個變數,$urn是一個內建於FUME ConceptMap的alias,轉譯出來為urn:ietf:rfc:3986
identifier.value是'urn:uuid:' 與 $pid這個變數的內容相連接,於是在範例中會顯示為 urn:uuid:$pid的內容
07 * identifier
08 * system = $exampleMrn
09 * value = mrn
第二組Patient.identifier,
identifier.system是$urn這個變數,$exampleMrn是一個內建於FUME ConceptMap的alias,轉譯出來為http://this.is.an.example.uri/mrn
identifier.value是INPUT端的mrn,PP875023983
10 * identifier
11 * system = $ssn
12 * value = ssn
第三組跟第二組的意義相同,就不贅述
13 * identifier
14 * system = $passportPrefix & passport_country
15 * value = passport_number
第四組的system是將$passportPrefix的內容與 輸入值passort_country相連,所以system最後輸出為http://hl7.org/fhir/sid/passport-USA
16 * active = status='active'
這行的意思是,active這個屬性項等於 (status = 'active')的boolean值,而status是輸入項,因為在這裡輸入項的status = 'active',
因此會輸出 "active": true
17 * name
18 * given = first_name
19 * family = last_name
name的屬性項下面分別有given與family,兩個各自對應輸入項的first_name與last_name
20 * birthDate = birth_date
birthDate的屬性項對應輸入birth_date,注意FUME會檢查這個項應填入的資料型態,必須為DateType否則會回報錯誤
21 * gender = $translate(sex, 'gender')
這行的意思是,gender的屬性項等於輸入項的sex,輸入項的sex將屬性項名稱轉為gender,使用這個function也必須要在conceptMap中有對應的轉換可用
22 * (address).address
23 * city = city_name
24 * state = state
25 * country = 'USA'
26 * line = $join([$string(house_number),street_name], ' ')
27 * postalCode = zip_code
28 * extension
29 * url = $extGeolocation
30 * extension
31 * url = 'latitude'
32 * valueDecimal = lat
33 * extension
34 * url = 'longitude'
35 * valueDecimal = long
整個address一起講,address對應到的是輸入端的address
"address": {
"city_name": "Orlando",
"state": "FL",
"street_name": "Buena Vista",
"house_number": 1375,
"zip_code": "3456701",
"lat": 28.3519592,
"long": -81.417283
}
這裡需要注意的是26行 * line = $join([$string(house_number),street_name], ' ')
這行的意思是先把house_number這個輸入轉換成String型態,然後與street_name兩個合併中間以' '間隔。
36 * (phones).telecom
37 * system = 'phone'
38 * value = number
39 * use = (type='HOME'?'home':type='CELL'?'mobile')
這邊要注意的是39行,39行是一個三元運算,這個運算子在C或較底層的語言很容易見到,
39行的意思是,若輸入的phones.type是'HOME',use這個屬性項等於'home'; 若輸入的phones.type是'CELL',use這個屬性項等於'mobile'
三元運算if-else幾乎貫穿了整個FUME Mapping的撰寫,如果讀者是第一次碰到也不要緊張
40 * generalPractitioner
41 * identifier
42 * value = primary_doctor.license
43 * type.coding
44 * system = 'http://terminology.hl7.org/CodeSystem/v2-0203'
45 * code = 'MD'
這裡要注意的是42行,42行是取用輸入的primary_doctor的license,FLASH可以使用.表示層級關係,但.在JSONata有其他意思,後面會說明
46 * display = primary_doctor.full_name
47 * reference = $literal('Practitioner', {'identifier': primary_doctor.license})
這邊只有47行得稍微解釋一下,$literal是FUME的內建function,作用類似於search,與search稍微不同的地方是,
$search是返回一個Searchset Bundle或單個resource,$literal只返回符合條件的resourceID,
也就是說,47行是去FHIR Server中找符合條件: identifier等於primary_doctor.license的Practitioner的Resource ID,達到引用的效果
看完今天的文章,讀者可以試試看找一些case來撰寫,試著摸一下FUME實際的效果,
有一些實作上我遇到的問題與克服方法會放在後面一點來談,因為實際上這個語言的撰寫很直覺,但運算與邏輯就比較底層一些了,要稍微習慣一下。
明天我會細講一些在FUME中JSONata可以做到的操作與一些函式的基本使用